#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include "log.hpp"
#include "common.hpp"
#include <sstream>
#include "log.hpp"
const std::string Sep = "\r\n";
const std::string BlankLine = "\r\n"; // 空行
const std::string LineSep = " ";      // 行分隔符
const std::string HeadLineSep = ": ";
const std::string HttpVersion = "HTTP/1.1";
const std::string defaulthomepage = "wwwroot";
const std::string page404 = "./wwwroot/404.html";
const std::string firstpage = "index.html";
using namespace LogModel;

class HttpRequest
{
public:
  HttpRequest()
  {
  }
  bool IsHasArgs()
  {
    return _isexec;
  }
  std::string Path()
  {
    return _path;
  }
  std::string Args()
  {
    return _args;
  }
  // Host: 101.126.23.53:8888
  // Connection: keep-alive
  // Cache-Control: max-age=0
  // Upgrade-Insecure-Requests: 1
  // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36
  // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
  // Accept-Encoding: gzip, deflate
  // Accept-Language: zh-CN,zh;q=0.9

  // ParseOneLine 返回值 out_string 未获取到值 并且返回值是false
  //       out_string 正确获得值 返回值是true
  //       out_string=substr(0,0) 是空串 返回值是true;

  void ParseHeaderKv()
  {
    std::string key, value;
    for (auto &head_line : _req_header)
    {
      if (SplitHeadKv(head_line, HeadLineSep, &key, &value))
      {
        _headerkv.insert(std::make_pair(key, value));
      }
    }
  }
  bool ParseHeader(std::string &header_string)
  {
    std::string out_string;
    while (true)
    {
      bool r = ParseOneLine(header_string, &out_string, Sep);
      if (!out_string.empty() && r)
      {
        _req_header.push_back(out_string);
      }
      else if (out_string.empty() && r)
      {
        _empty_line = BlankLine;
        break;
      }
      else
      {
        return false;
      }
    }
    ParseHeaderKv();
    return true;
  }

  bool Deserialization(std::string &req_str)
  {
    if (ParseOneLine(req_str, &_req_line, Sep))
    {
      ParseReqLine(_req_line, LineSep);
      ParseHeader(req_str);
      _body = req_str;

      if (_method == "POST")
      {
        if (!_body.empty())
        {
          _isexec = true;
          _path = _uri;
          _args = _body;
          LOG(LogLevel::DEBUG) << "POST: PATH:    " << _path;
          LOG(LogLevel::DEBUG) << "POST: ARGS:    " << _args;
        }
      }
      else if (_method == "GET")
      {
        auto pos = _uri.find('?');
        if (pos != std::string::npos)
        {
          _isexec = true;
          _path = _uri.substr(0, pos);
          _args = _uri.substr(pos + 1);
          LOG(LogLevel::DEBUG) << "GET: PATH" << _path;
          LOG(LogLevel::DEBUG) << "GET: ARGS" << _args;
        }
      }
    }
  return true;
} 

//_req_line = GET / HTTP/1.1

std::string GetContent(const std::string uri_path)
{
  std::string content;
  std::ifstream in(uri_path, std::ios::binary);
  if (!in.is_open())
    return std::string();
  in.seekg(0, in.end);
  int filesize = in.tellg();
  in.seekg(0, in.beg);

  content.resize(filesize);
  in.read((char *)content.c_str(), filesize);
  in.close();
  // LOG(LogLevel::DEBUG) << "content length: " << content.size();
  return content;
}

void Print()
{
  std::cout << "method: " << _method << std::endl;
  std::cout << "uri " << _uri << std::endl;
  std::cout << "version: " << _version << std::endl;

  for (auto &key : _headerkv)
  {
    std::cout << key.first << std::endl;
    std::cout << key.second << std::endl;
  }
  std::cout << _empty_line << "-------------------";
  std::cout << _body;
}
std::string Uri()
{
  return _uri;
}
void SetUri(const std::string newuri)
{
  _uri = newuri;
}
// 截取后缀
std::string Suffix()
{
  // _uri -> wwwroot/index.html wwwroot/image/1.jpg wwwroot/login.html
  auto pos = _uri.rfind(".");
  if (pos == std::string::npos)
    return std::string(".html");
  else
    return _uri.substr(pos);
}

~HttpRequest()
{
}

private:
void ParseReqLine(std::string &_req_line, const std::string sep)
{
  (void)sep;
  std::stringstream ss(_req_line);
  ss >> _method >> _uri >> _version;
}

private:
std::string _req_line;
std::vector<std::string> _req_header;
std::string _empty_line;
std::string _body;

std::string _method;
std::string _uri;
std::string _version;
// 存放_req_header中的键值对
std::unordered_map<std::string, std::string> _headerkv;
// 判断是否需要与前端页面交互
bool _isexec = false;
std::string _path;
std::string _args;
}
;

class HttpRespond
{
public:
  HttpRespond() : _version(HttpVersion)
  {
  }
  ~HttpRespond()
  {
  }
  bool Build(HttpRequest &req)
  {
    // newuri = wwwroot/a/b/c
    std::string newuri = defaulthomepage + req.Uri();
    if (newuri.back() == '/')
    {
      newuri += firstpage;
    }
    // req.SetUri(newuri);
    _content = req.GetContent(newuri);
    // 根据拿到的内容 进行返回码的设置
    if (_content.empty())
    {
      _status_code = 404;
      _content = req.GetContent(page404);
    }
    else
    {
      _status_code = 200;
    }
    _status_desc = Code2Desc(_status_code);
    if (!_content.empty())
    {
      std::string content_length = std::to_string(_content.size());
      SetHeader("content-length", content_length);
    }
    std::string mintype = Suffix2Desc(req.Suffix());
    SetHeader("Content-type", mintype);
    _body = _content;
    return true;
  }
  bool Serialization(std::string *in_string)
  {
    _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;
    for (auto &head : _header_kv)
    {
      _resp_header.push_back(head.first + HeadLineSep + head.second);
    }
    _blank_line = Sep;
    *in_string = _resp_line;
    for (auto &head_line : _resp_header)
    {
      *in_string += (head_line + Sep);
    }
    *in_string += _blank_line;
    *in_string += _body;
    return true;
  }
  void SetCode(int code)
  {
    _status_code = code;
  }
  void SetBody(std::string &body)
  {
    _body = body;
  }
  void SetHeader(const std::string k, const std::string v)
  {
    _header_kv[k] = v;
  }

private:
  std::string Code2Desc(int code)
  {
    switch (code)
    {
    case 200:
      return "OK";
    case 404:
      return "Not Found";
    case 301:
      return "Moved Permanently";
    case 302:
      return "Found";
    default:
      return std::string();
    }
  }
  std::string Suffix2Desc(const std::string &suffix)
  {
    if (suffix == ".html")
      return "text/html";
    else if (suffix == ".jpg")
      return "application/x-jpg";
    else
      return "text/html";
  }

private:
  std::string _version;
  int _status_code;
  std::string _status_desc;
  std::string _content;
  std::unordered_map<std::string, std::string> _header_kv;

  // 最终要这4部分，构建应答
  std::string _resp_line;
  std::vector<std::string> _resp_header;
  std::string _blank_line;
  std::string _body;
};